Generator와 async-await
🧑🏻💻 Generator
yeild
키워드와next
메서드를 통해 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할 수 있는 특수한 함수다.function*
키워드로 선언하며 하나 이상의 yield 표현식을 포함한다.화살표 함수나 생성자 함수로 선언 및 호출할 수 없다.
//제너레이터 함수 선언문
function* genDecFunc() {
yield 1;
}
//제너레이터 함수 표현식
const genExpFunc = function* () {
yield 1;
};
//제너레이터 메서드
const obj = {
* genObiMethod( ) {
yield 1;
}
};
//제너레이터 클래스 메서드
class MyClass {
* genClsMethod() {
yield 1;
}
}
✅ Generator와 일반 함수의 차이
- non-blocking 가능 여부
- 일반 함수 → 함수 호출자가 함수를 호출한 이후 함수 실행을 제어할 수 없다.
- Generator 함수 → 함수 호출자에게 함수 실행의 제어권을 양도할 수 있다.
- 함수의 상태 전달
- 일반 함수 → 함수가 실행되고 있는 동안에는 함수 외부에서 함수 내부르 값을 전달하여 함수의 상태를 변경할 수 없다.
- Generator 함수 → 함수 호출자와 함수의 상태를 양방향으로 주고받을 수 있다.
- 반환 값
- 일반 함수 → 호출하면 함수 코드를 일괄 실행하고 값을 반환한다.
- Generator → 호출하면 이터러블이면서 이터레이터인 Generator 객체를 반환한다.
✅ Generator의 반환값 Generator 객체
Generator 객체는
Symbol.iterator
메서드를 상속받는 이터러블이면서value
,done
프로퍼티와next
메서드를 가지는 이터레이터다.여기에 추가로
return
,throw
메서드를 갖는다.
🧑🏻💻 async/await
✅ 사용 효과
const fetch = require("node-fetch");
async function fetchTodo() {
try {
const url = 'https://jsonplaceholder.typicode.com/todos/1';
const response = await fetch(url);
const todo = await response.json();
} catch (e) {
console.log(e);
}
}
ES8에 나온
async/await
를 사용하면, 제너레이터보다 간단하고 가독성 좋게 비동기 처리를 동기 처리처럼 동작하도록 구현 할 수 있다.async/await
는 프로미스를 기반으로 동작하지만 프로미스의then/catch/finally
와 같은 후속 메서드 없이도 동기 처리처럼 프로미스가 처리 결과를 반환하도록 구현할 수 있다. (물론 사용은 할 수 있다.)async/await
에서는 비동기 함수를 명시적으로 호출할 수 있기 때문에 호출자가 명확하다. 이 덕분에try … catch
문을 사용하여 try 블록 내 모든 에러를 한번에 캐치할 수 있다.
✅ async 함수
async 함수는 언제나 프로미스를 반환한다.
클래스의 constructor 메서드와 async 메서드는 각각 인스턴스와 프로미스를 항상 반환해야 하므로, constructor 메서드는 async 메서드가 될 수 없다.
✅ await 키워드
await 키워드는 반드시 async 함수 내부에서 사용해야 한다.
await 키워드는 반드시 Promise 를 반환하는 함수 앞 혹은 Promise 앞에서 사용해야 한다.
await 키워드를 남발하지 말자.
async function foo() {
const res = await Promise.all([
new Promise(resolve => setTimeout(() => resolve(1), 3000)),
new Promise(resolve => setTimeout(() => resolve(2), 2000)),
new Promise(resolve => setTimeout(() => resolve(3), 1000))
]);
console. log(res); // [1, 2, 3]
}
foo(); // 약 3초 소요된다.
- foo 함수가 수행하는 3개의 비동기 처리는 서로 연관이 없이 개별적으로 수행되는 비동기 처리이다. 하지만 결과 값은 순서대로 출력된다.
async function foo() {
const a = await new Promise(resolve => setTimeout(() => resolve(1), 3000));
const b = await new Promise(resolve => setTimeout (() => resolve (2), 2000));
const c = await new Promise (resolve =› setTimeout(() => resolve(3), 1000));
console. log([a, b, c]); // [1, 2, 3]
}
foo(); // 약 6초 소요된다.
- 각 동작에 await를 추가하면 결과는 똑같지만 더 오래 걸린다.
참고 자료
- 모던 자바스크립트 Deep Dive